{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d6f842bf",
   "metadata": {},
   "source": [
    "# Drawing Graph Edges Using `geomSegment()` and `geomCurve()`\n",
    "\n",
    "Beyond merely connecting two points on a chart, the `geomSegment()` and `geomCurve()` geometries</br>\n",
    "can, with some fine-tuning, help to visualize graph-like data.\n",
    "\n",
    "Use aesthetics `sizeStart/End` and `strokeStart/End` to allow `segment/curve`</br>\n",
    "to take into account the size of the point from which it starts/ends and to avoid drawing over it.\n",
    "\n",
    "Utilize the `spacer` parameter for further manual fine-tuning."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5c5fdd1b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "            <div id=\"kotlin_out_0\"/>\n",
       "            <script type=\"text/javascript\">\n",
       "                            if(!window.kotlinQueues) {\n",
       "                window.kotlinQueues = {};\n",
       "            }\n",
       "            if(!window.kotlinQueues[\"DataFrame\"]) {\n",
       "                var resQueue = [];\n",
       "                window.kotlinQueues[\"DataFrame\"] = resQueue;\n",
       "                window[\"call_DataFrame\"] = function(f) {\n",
       "                    resQueue.push(f);\n",
       "                }\n",
       "            }\n",
       "            (function (){\n",
       "                var modifiers = [(function(script) {\n",
       "    script.src = \"https://cdn.jsdelivr.net/gh/Kotlin/dataframe@d6467c1389bc031958acd5310fce39167b5cc581/src/main/resources/init.js\"\n",
       "    script.type = \"text/javascript\";\n",
       "})];\n",
       "                var e = document.getElementById(\"kotlin_out_0\");\n",
       "                modifiers.forEach(function (gen) {\n",
       "                    var script = document.createElement(\"script\");\n",
       "                    gen(script)\n",
       "                    script.addEventListener(\"load\", function() {\n",
       "                        window[\"call_DataFrame\"] = function(f) {f();};\n",
       "                        window.kotlinQueues[\"DataFrame\"].forEach(function(f) {f();});\n",
       "                        window.kotlinQueues[\"DataFrame\"] = [];\n",
       "                    }, false);\n",
       "                    script.addEventListener(\"error\", function() {\n",
       "                        window[\"call_DataFrame\"] = function(f) {};\n",
       "                        window.kotlinQueues[\"DataFrame\"] = [];\n",
       "                        var div = document.createElement(\"div\");\n",
       "                        div.style.color = 'darkred';\n",
       "                        div.textContent = 'Error loading resource DataFrame';\n",
       "                        document.getElementById(\"kotlin_out_0\").appendChild(div);\n",
       "                    }, false);\n",
       "                    \n",
       "                    e.appendChild(script);\n",
       "                });\n",
       "            })();\n",
       "            </script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "                <style>\n",
       "                :root {\n",
       "    --background: #fff;\n",
       "    --background-odd: #f5f5f5;\n",
       "    --background-hover: #d9edfd;\n",
       "    --header-text-color: #474747;\n",
       "    --text-color: #848484;\n",
       "    --text-color-dark: #000;\n",
       "    --text-color-medium: #737373;\n",
       "    --text-color-pale: #b3b3b3;\n",
       "    --inner-border-color: #aaa;\n",
       "    --bold-border-color: #000;\n",
       "    --link-color: #296eaa;\n",
       "    --link-color-pale: #296eaa;\n",
       "    --link-hover: #1a466c;\n",
       "}\n",
       "\n",
       ":root[theme=\"dark\"], :root [data-jp-theme-light=\"false\"]{\n",
       "    --background: #303030;\n",
       "    --background-odd: #3c3c3c;\n",
       "    --background-hover: #464646;\n",
       "    --header-text-color: #dddddd;\n",
       "    --text-color: #b3b3b3;\n",
       "    --text-color-dark: #dddddd;\n",
       "    --text-color-medium: #b2b2b2;\n",
       "    --text-color-pale: #737373;\n",
       "    --inner-border-color: #707070;\n",
       "    --bold-border-color: #777777;\n",
       "    --link-color: #008dc0;\n",
       "    --link-color-pale: #97e1fb;\n",
       "    --link-hover: #00688e;\n",
       "}\n",
       "\n",
       "table.dataframe {\n",
       "    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n",
       "    font-size: 12px;\n",
       "    background-color: var(--background);\n",
       "    color: var(--text-color-dark);\n",
       "    border: none;\n",
       "    border-collapse: collapse;\n",
       "}\n",
       "\n",
       "table.dataframe th, td {\n",
       "    padding: 6px;\n",
       "    border: 1px solid transparent;\n",
       "    text-align: left;\n",
       "}\n",
       "\n",
       "table.dataframe th {\n",
       "    background-color: var(--background);\n",
       "    color: var(--header-text-color);\n",
       "}\n",
       "\n",
       "table.dataframe td {\n",
       "    vertical-align: top;\n",
       "}\n",
       "\n",
       "table.dataframe th.bottomBorder {\n",
       "    border-bottom-color: var(--bold-border-color);\n",
       "}\n",
       "\n",
       "table.dataframe tbody > tr:nth-child(odd) {\n",
       "    background: var(--background-odd);\n",
       "}\n",
       "\n",
       "table.dataframe tbody > tr:nth-child(even) {\n",
       "    background: var(--background);\n",
       "}\n",
       "\n",
       "table.dataframe tbody > tr:hover {\n",
       "    background: var(--background-hover);\n",
       "}\n",
       "\n",
       "table.dataframe a {\n",
       "    cursor: pointer;\n",
       "    color: var(--link-color);\n",
       "    text-decoration: none;\n",
       "}\n",
       "\n",
       "table.dataframe tr:hover > td a {\n",
       "    color: var(--link-color-pale);\n",
       "}\n",
       "\n",
       "table.dataframe a:hover {\n",
       "    color: var(--link-hover);\n",
       "    text-decoration: underline;\n",
       "}\n",
       "\n",
       "table.dataframe img {\n",
       "    max-width: fit-content;\n",
       "}\n",
       "\n",
       "table.dataframe th.complex {\n",
       "    background-color: var(--background);\n",
       "    border: 1px solid var(--background);\n",
       "}\n",
       "\n",
       "table.dataframe .leftBorder {\n",
       "    border-left-color: var(--inner-border-color);\n",
       "}\n",
       "\n",
       "table.dataframe .rightBorder {\n",
       "    border-right-color: var(--inner-border-color);\n",
       "}\n",
       "\n",
       "table.dataframe .rightAlign {\n",
       "    text-align: right;\n",
       "}\n",
       "\n",
       "table.dataframe .expanderSvg {\n",
       "    width: 8px;\n",
       "    height: 8px;\n",
       "    margin-right: 3px;\n",
       "}\n",
       "\n",
       "table.dataframe .expander {\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "}\n",
       "\n",
       "/* formatting */\n",
       "\n",
       "table.dataframe .null {\n",
       "    color: var(--text-color-pale);\n",
       "}\n",
       "\n",
       "table.dataframe .structural {\n",
       "    color: var(--text-color-medium);\n",
       "    font-weight: bold;\n",
       "}\n",
       "\n",
       "table.dataframe .dataFrameCaption {\n",
       "    font-weight: bold;\n",
       "}\n",
       "\n",
       "table.dataframe .numbers {\n",
       "    color: var(--text-color-dark);\n",
       "}\n",
       "\n",
       "table.dataframe td:hover .formatted .structural, .null {\n",
       "    color: var(--text-color-dark);\n",
       "}\n",
       "\n",
       "table.dataframe tr:hover .formatted .structural, .null {\n",
       "    color: var(--text-color-dark);\n",
       "}\n",
       "\n",
       "\n",
       "                </style>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "   <div id=\"Jh7nbk\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"library\">\n",
       "       if(!window.letsPlotCallQueue) {\n",
       "           window.letsPlotCallQueue = [];\n",
       "       }; \n",
       "       window.letsPlotCall = function(f) {\n",
       "           window.letsPlotCallQueue.push(f);\n",
       "       };\n",
       "       (function() {\n",
       "           var script = document.createElement(\"script\");\n",
       "           script.type = \"text/javascript\";\n",
       "           script.src = \"https://cdn.jsdelivr.net/gh/JetBrains/lets-plot@v4.3.0rc1/js-package/distr/lets-plot.min.js\";\n",
       "           script.onload = function() {\n",
       "               window.letsPlotCall = function(f) {f();};\n",
       "               window.letsPlotCallQueue.forEach(function(f) {f();});\n",
       "               window.letsPlotCallQueue = [];\n",
       "               \n",
       "               \n",
       "           };\n",
       "           script.onerror = function(event) {\n",
       "               window.letsPlotCall = function(f) {};\n",
       "               window.letsPlotCallQueue = [];\n",
       "               var div = document.createElement(\"div\");\n",
       "               div.style.color = 'darkred';\n",
       "               div.textContent = 'Error loading Lets-Plot JS';\n",
       "               document.getElementById(\"Jh7nbk\").appendChild(div);\n",
       "           };\n",
       "           var e = document.getElementById(\"Jh7nbk\");\n",
       "           e.appendChild(script);\n",
       "       })();\n",
       "   </script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%useLatestDescriptors\n",
    "%use lets-plot\n",
    "%use dataframe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d0c295e8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Lets-Plot Kotlin API v.0.0.0-SNAPSHOT. Frontend: Notebook with dynamically loaded JS. Lets-Plot JS v.4.3.0rc1."
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "LetsPlot.getInfo()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "e76d6822",
   "metadata": {},
   "outputs": [],
   "source": [
    "val x = listOf(-1, 0, 1)\n",
    "val y = listOf(-1, 1, -1)\n",
    "val shape = listOf(1, 16, 21)\n",
    "val size = listOf(1, 2, 3)\n",
    "val stroke = listOf(1, 0, 2)\n",
    "\n",
    "val verticesData = mapOf(\n",
    "    \"x\" to x,\n",
    "    \"y\" to y,\n",
    "    \"shape\" to shape,\n",
    "    \"size\" to size,\n",
    "    \"stroke\" to stroke\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "89d4eccb",
   "metadata": {},
   "outputs": [],
   "source": [
    "val verticesLayer = geomPoint(color = \"#4575b4\", fill = \"#abd9e9\") {\n",
    "    x = \"x\"; y = \"y\"; size = \"size\"; shape = \"shape\"; stroke = \"stroke\"\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "75bc4cb3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"g3n7r6\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
       "       (function() {\n",
       "           var plotSpec={\n",
       "\"mapping\":{\n",
       "},\n",
       "\"data\":{\n",
       "\"shape\":[1.0,16.0,21.0],\n",
       "\"size\":[1.0,2.0,3.0],\n",
       "\"x\":[-1.0,0.0,1.0],\n",
       "\"y\":[-1.0,1.0,-1.0],\n",
       "\"stroke\":[1.0,0.0,2.0]\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[{\n",
       "\"aesthetic\":\"size\",\n",
       "\"range\":[20.0,30.0],\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"stroke\",\n",
       "\"range\":[0.0,10.0],\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"shape\",\n",
       "\"discrete\":true,\n",
       "\"scale_mapper_kind\":\"identity\",\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"x\",\n",
       "\"limits\":[-1.5,1.5]\n",
       "},{\n",
       "\"aesthetic\":\"y\",\n",
       "\"limits\":[-1.5,1.5]\n",
       "}],\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"shape\":\"shape\",\n",
       "\"size\":\"size\",\n",
       "\"stroke\":\"stroke\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"color\":\"#4575b4\",\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"point\",\n",
       "\"fill\":\"#abd9e9\",\n",
       "\"data\":{\n",
       "}\n",
       "}]\n",
       "};\n",
       "           var plotContainer = document.getElementById(\"g3n7r6\");\n",
       "           window.letsPlotCall(function() {{\n",
       "               LetsPlot.buildPlotFromProcessedSpecs(plotSpec, -1, -1, plotContainer);\n",
       "           }});\n",
       "       })();    \n",
       "   </script>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val graphVertices =\n",
    "    letsPlot(verticesData) + verticesLayer + \n",
    "    scaleSize(range = 20 to 30, guide = \"none\") + \n",
    "    scaleStroke(range = 0 to 10, guide = \"none\") +\n",
    "    scaleShapeIdentity() +\n",
    "    lims(x = -1.5 to 1.5, y = -1.5 to 1.5)\n",
    "\n",
    "graphVertices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "ecc10732",
   "metadata": {},
   "outputs": [],
   "source": [
    "val edgesData = mapOf(\n",
    "    \"xEnd\" to x.toMutableList().apply { this.add(this.removeFirst()) },\n",
    "    \"yEnd\" to y.toMutableList().apply { this.add(this.removeFirst()) }\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6f3d83ee",
   "metadata": {},
   "source": [
    "#### 1. Draw Ugly Graph Edges"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "59a6e52d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"BFP3KV\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
       "       (function() {\n",
       "           var plotSpec={\n",
       "\"mapping\":{\n",
       "},\n",
       "\"data\":{\n",
       "\"shape\":[1.0,16.0,21.0],\n",
       "\"size\":[1.0,2.0,3.0],\n",
       "\"x\":[-1.0,0.0,1.0],\n",
       "\"y\":[-1.0,1.0,-1.0],\n",
       "\"stroke\":[1.0,0.0,2.0]\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[{\n",
       "\"aesthetic\":\"size\",\n",
       "\"range\":[20.0,30.0],\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"stroke\",\n",
       "\"range\":[0.0,10.0],\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"shape\",\n",
       "\"discrete\":true,\n",
       "\"scale_mapper_kind\":\"identity\",\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"x\",\n",
       "\"limits\":[-1.5,1.5]\n",
       "},{\n",
       "\"aesthetic\":\"y\",\n",
       "\"limits\":[-1.5,1.5]\n",
       "}],\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"shape\":\"shape\",\n",
       "\"size\":\"size\",\n",
       "\"stroke\":\"stroke\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"color\":\"#4575b4\",\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"point\",\n",
       "\"fill\":\"#abd9e9\",\n",
       "\"data\":{\n",
       "}\n",
       "},{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"xend\":\"xEnd\",\n",
       "\"yend\":\"yEnd\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"xEnd\":[0.0,1.0,-1.0],\n",
       "\"yEnd\":[1.0,-1.0,-1.0]\n",
       "},\n",
       "\"arrow\":{\n",
       "\"name\":\"arrow\",\n",
       "\"ends\":\"both\"\n",
       "},\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"segment\"\n",
       "}]\n",
       "};\n",
       "           var plotContainer = document.getElementById(\"BFP3KV\");\n",
       "           window.letsPlotCall(function() {{\n",
       "               LetsPlot.buildPlotFromProcessedSpecs(plotSpec, -1, -1, plotContainer);\n",
       "           }});\n",
       "       })();    \n",
       "   </script>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val uglyEdges = geomSegment(data = edgesData, arrow = arrow(ends = \"both\")) {\n",
    "    x = \"x\"; y = \"y\"; xend = \"xEnd\"; yend = \"yEnd\"\n",
    "} \n",
    "\n",
    "graphVertices + uglyEdges"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6efc71e",
   "metadata": {},
   "source": [
    "#### 2. Draw Nice Graph Edges"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "fabb7673",
   "metadata": {},
   "outputs": [],
   "source": [
    "// Append an info on the sizes of vertices in the graph.\n",
    "val edgesData2 = edgesData + mapOf(\n",
    "    \"sizeEnd\" to size.toMutableList().apply { this.add(this.removeFirst()) },\n",
    "    \"strokeEnd\" to stroke.toMutableList().apply { this.add(this.removeFirst()) }\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "94e3bed0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"vrzd9L\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
       "       (function() {\n",
       "           var plotSpec={\n",
       "\"layout\":{\n",
       "\"name\":\"grid\",\n",
       "\"ncol\":2,\n",
       "\"nrow\":1,\n",
       "\"fit\":true,\n",
       "\"align\":false\n",
       "},\n",
       "\"figures\":[{\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"shape\":\"shape\",\n",
       "\"size\":\"size\",\n",
       "\"stroke\":\"stroke\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"color\":\"#4575b4\",\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"point\",\n",
       "\"fill\":\"#abd9e9\",\n",
       "\"data\":{\n",
       "}\n",
       "},{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"xend\":\"xEnd\",\n",
       "\"yend\":\"yEnd\",\n",
       "\"size_start\":\"size\",\n",
       "\"size_end\":\"sizeEnd\",\n",
       "\"stroke_start\":\"stroke\",\n",
       "\"stroke_end\":\"strokeEnd\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"xEnd\":[0.0,1.0,-1.0],\n",
       "\"sizeEnd\":[2.0,3.0,1.0],\n",
       "\"strokeEnd\":[0.0,2.0,1.0],\n",
       "\"yEnd\":[1.0,-1.0,-1.0]\n",
       "},\n",
       "\"arrow\":{\n",
       "\"name\":\"arrow\",\n",
       "\"ends\":\"both\"\n",
       "},\n",
       "\"spacer\":5.0,\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"segment\"\n",
       "}],\n",
       "\"mapping\":{\n",
       "},\n",
       "\"data\":{\n",
       "\"shape\":[1.0,16.0,21.0],\n",
       "\"size\":[1.0,2.0,3.0],\n",
       "\"x\":[-1.0,0.0,1.0],\n",
       "\"y\":[-1.0,1.0,-1.0],\n",
       "\"stroke\":[1.0,0.0,2.0]\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[{\n",
       "\"aesthetic\":\"size\",\n",
       "\"range\":[20.0,30.0],\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"stroke\",\n",
       "\"range\":[0.0,10.0],\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"shape\",\n",
       "\"discrete\":true,\n",
       "\"scale_mapper_kind\":\"identity\",\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"x\",\n",
       "\"limits\":[-1.5,1.5]\n",
       "},{\n",
       "\"aesthetic\":\"y\",\n",
       "\"limits\":[-1.5,1.5]\n",
       "}]\n",
       "},{\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"shape\":\"shape\",\n",
       "\"size\":\"size\",\n",
       "\"stroke\":\"stroke\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"color\":\"#4575b4\",\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"point\",\n",
       "\"fill\":\"#abd9e9\",\n",
       "\"data\":{\n",
       "}\n",
       "},{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"xend\":\"xEnd\",\n",
       "\"yend\":\"yEnd\",\n",
       "\"size_start\":\"size\",\n",
       "\"size_end\":\"sizeEnd\",\n",
       "\"stroke_start\":\"stroke\",\n",
       "\"stroke_end\":\"strokeEnd\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"xEnd\":[0.0,1.0,-1.0],\n",
       "\"sizeEnd\":[2.0,3.0,1.0],\n",
       "\"strokeEnd\":[0.0,2.0,1.0],\n",
       "\"yEnd\":[1.0,-1.0,-1.0]\n",
       "},\n",
       "\"arrow\":{\n",
       "\"name\":\"arrow\",\n",
       "\"ends\":\"both\"\n",
       "},\n",
       "\"spacer\":5.0,\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"curve\",\n",
       "\"curvature\":-0.3\n",
       "}],\n",
       "\"mapping\":{\n",
       "},\n",
       "\"data\":{\n",
       "\"shape\":[1.0,16.0,21.0],\n",
       "\"size\":[1.0,2.0,3.0],\n",
       "\"x\":[-1.0,0.0,1.0],\n",
       "\"y\":[-1.0,1.0,-1.0],\n",
       "\"stroke\":[1.0,0.0,2.0]\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[{\n",
       "\"aesthetic\":\"size\",\n",
       "\"range\":[20.0,30.0],\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"stroke\",\n",
       "\"range\":[0.0,10.0],\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"shape\",\n",
       "\"discrete\":true,\n",
       "\"scale_mapper_kind\":\"identity\",\n",
       "\"guide\":\"none\"\n",
       "},{\n",
       "\"aesthetic\":\"x\",\n",
       "\"limits\":[-1.5,1.5]\n",
       "},{\n",
       "\"aesthetic\":\"y\",\n",
       "\"limits\":[-1.5,1.5]\n",
       "}]\n",
       "}],\n",
       "\"kind\":\"subplots\"\n",
       "};\n",
       "           var plotContainer = document.getElementById(\"vrzd9L\");\n",
       "           window.letsPlotCall(function() {{\n",
       "               LetsPlot.buildPlotFromProcessedSpecs(plotSpec, -1, -1, plotContainer);\n",
       "           }});\n",
       "       })();    \n",
       "   </script>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// Use `segment` and then `curve` to draw \"nice\" edges.\n",
    "\n",
    "val niceEdgesS = \n",
    "    geomSegment(\n",
    "        data = edgesData2,       \n",
    "        arrow = arrow(ends = \"both\"),\n",
    "        spacer = 5                                       // New! Add a \"spacer\".\n",
    "    ) {\n",
    "        x = \"x\"; y = \"y\"; xend = \"xEnd\"; yend = \"yEnd\";\n",
    "        sizeStart = \"size\"; sizeEnd = \"sizeEnd\";         // New! Take into account sizes of points \n",
    "                                                         // connected by the edge.\n",
    "        strokeStart = \"stroke\"; strokeEnd = \"strokeEnd\"  // New! Take into account stroke (width) of points \n",
    "                                                         // connected by the edge.\n",
    "    }\n",
    "\n",
    "val niceEdgesC = geomCurve(\n",
    "        data = edgesData2,       \n",
    "        arrow = arrow(ends = \"both\"),\n",
    "        curvature = -0.3,\n",
    "        spacer = 5\n",
    "    ) {\n",
    "        x = \"x\"; y = \"y\"; xend = \"xEnd\"; yend = \"yEnd\";\n",
    "        sizeStart = \"size\"; sizeEnd = \"sizeEnd\";\n",
    "        strokeStart = \"stroke\"; strokeEnd = \"strokeEnd\"\n",
    "    }\n",
    "\n",
    "gggrid(listOf(\n",
    "    graphVertices + niceEdgesS,\n",
    "    graphVertices + niceEdgesC\n",
    "))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "442f6d5a",
   "metadata": {},
   "source": [
    "#### 3. Another Example of Graph Visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ecbbd3be",
   "metadata": {},
   "outputs": [],
   "source": [
    "val nodesDf = dataFrameOf(\n",
    "    \"node\" to listOf(\"Living\\nThings\", \"Animals\", \"Plants\", \"Dogs\", \"Cows\", \"Herbs\"),\n",
    "    \"x\" to listOf(0, -1, 1, -2, 0, 2),\n",
    "    \"y\" to listOf(1, 0, 0, -1, -1, -1)\n",
    ")\n",
    "\n",
    "var edgesDf = dataFrameOf(\n",
    "    \"from\" to listOf(\"Animals\", \"Plants\", \"Dogs\", \"Cows\", \"Cows\", \"Herbs\"),\n",
    "    \"to\" to listOf(\"Living\\nThings\", \"Living\\nThings\", \"Animals\", \"Animals\", \"Herbs\", \"Plants\"),\n",
    "    \"relation\" to listOf(\"is\", \"is\", \"is\", \"is\", \"eat\", \"is\")\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "08bf4b9d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "        <html>\n",
       "        <head>\n",
       "            <style type=\"text/css\">\n",
       "                \n",
       "\n",
       "            </style>\n",
       "        </head>\n",
       "        <body>\n",
       "            <table class=\"dataframe\" id=\"df_1459617792\"></table>\n",
       "\n",
       "<p>DataFrame: rowsCount = 6, columnsCount = 7</p>\n",
       "        </body>\n",
       "        <script>\n",
       "            /*<!--*/\n",
       "call_DataFrame(function() { DataFrame.addTable({ cols: [{ name: \"<span title=\\\"from: String\\\">from</span>\", children: [], rightAlign: false, values: [\"Animals\",\"Plants\",\"Dogs\",\"Cows\",\"Cows\",\"Herbs\"] }, \n",
       "{ name: \"<span title=\\\"to: String\\\">to</span>\", children: [], rightAlign: false, values: [\"Living\\nThings\",\"Living\\nThings\",\"Animals\",\"Animals\",\"Herbs\",\"Plants\"] }, \n",
       "{ name: \"<span title=\\\"relation: String\\\">relation</span>\", children: [], rightAlign: false, values: [\"is\",\"is\",\"is\",\"is\",\"eat\",\"is\"] }, \n",
       "{ name: \"<span title=\\\"xTo: Int\\\">xTo</span>\", children: [], rightAlign: true, values: [\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">0</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">0</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">-1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">-1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">2</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">1</span></span>\"] }, \n",
       "{ name: \"<span title=\\\"yTo: Int\\\">yTo</span>\", children: [], rightAlign: true, values: [\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">0</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">0</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">-1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">0</span></span>\"] }, \n",
       "{ name: \"<span title=\\\"x: Int\\\">x</span>\", children: [], rightAlign: true, values: [\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">-1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">-2</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">0</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">0</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">2</span></span>\"] }, \n",
       "{ name: \"<span title=\\\"y: Int\\\">y</span>\", children: [], rightAlign: true, values: [\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">0</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">0</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">-1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">-1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">-1</span></span>\",\"<span class=\\\"formatted\\\" title=\\\"\\\"><span class=\\\"numbers\\\">-1</span></span>\"] }, \n",
       "], id: 1459617792, rootId: 1459617792, totalRows: 6 } ) });\n",
       "/*-->*/\n",
       "\n",
       "call_DataFrame(function() { DataFrame.renderTable(1459617792) });\n",
       "\n",
       "\n",
       "        </script>\n",
       "        </html>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "edgesDf = edgesDf.join(nodesDf) { to match right.node }.rename(Pair(\"x\", \"xTo\")).rename(Pair(\"y\", \"yTo\"))\n",
    "edgesDf = edgesDf.join(nodesDf) { from match right.node }\n",
    "edgesDf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "b82cc8d5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"CVhUFt\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
       "       (function() {\n",
       "           var plotSpec={\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\"\n",
       "},\n",
       "\"coord\":{\n",
       "\"name\":\"cartesian\",\n",
       "\"xlim\":[-3.0,3.0],\n",
       "\"flip\":false,\n",
       "\"ylim\":[-1.5,1.5]\n",
       "},\n",
       "\"data\":{\n",
       "\"node\":[\"Living\\nThings\",\"Animals\",\"Plants\",\"Dogs\",\"Cows\",\"Herbs\"],\n",
       "\"x\":[0.0,-1.0,1.0,-2.0,0.0,2.0],\n",
       "\"y\":[1.0,0.0,0.0,-1.0,-1.0,-1.0]\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[{\n",
       "\"aesthetic\":\"color\",\n",
       "\"values\":[\"#2166ac\",\"#d6604d\"]\n",
       "}],\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"xend\":\"xTo\",\n",
       "\"yend\":\"yTo\",\n",
       "\"color\":\"relation\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"xTo\":[0.0,0.0,-1.0,-1.0,2.0,1.0],\n",
       "\"yTo\":[1.0,1.0,0.0,0.0,-1.0,0.0],\n",
       "\"x\":[-1.0,1.0,-2.0,0.0,0.0,2.0],\n",
       "\"y\":[0.0,0.0,-1.0,-1.0,-1.0,-1.0],\n",
       "\"relation\":[\"is\",\"is\",\"is\",\"is\",\"eat\",\"is\"]\n",
       "},\n",
       "\"arrow\":{\n",
       "\"name\":\"arrow\"\n",
       "},\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"segment\",\n",
       "\"size_end\":25.0\n",
       "},{\n",
       "\"mapping\":{\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"color\":\"#2166ac\",\n",
       "\"shape\":21.0,\n",
       "\"size\":25.0,\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"point\",\n",
       "\"fill\":\"#d1e5f0\",\n",
       "\"data\":{\n",
       "}\n",
       "},{\n",
       "\"mapping\":{\n",
       "\"label\":\"node\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"text\",\n",
       "\"data\":{\n",
       "}\n",
       "}],\n",
       "\"theme\":{\n",
       "\"name\":\"classic\",\n",
       "\"axis\":{\n",
       "\"blank\":true\n",
       "},\n",
       "\"line\":{\n",
       "\"blank\":true\n",
       "}\n",
       "}\n",
       "};\n",
       "           var plotContainer = document.getElementById(\"CVhUFt\");\n",
       "           window.letsPlotCall(function() {{\n",
       "               LetsPlot.buildPlotFromProcessedSpecs(plotSpec, -1, -1, plotContainer);\n",
       "           }});\n",
       "       })();    \n",
       "   </script>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letsPlot(nodesDf.toMap()) { x = \"x\"; y = \"y\" } +\n",
    "    geomSegment(data = edgesDf.toMap(), sizeEnd = 25, arrow = arrow()) { \n",
    "        x = \"x\"; y = \"y\"; xend = \"xTo\"; yend = \"yTo\"; color = \"relation\" \n",
    "    } +\n",
    "    geomPoint(color = \"#2166ac\", fill = \"#d1e5f0\", shape = 21, size = 25) +\n",
    "    scaleColorManual(listOf(\"#2166ac\", \"#d6604d\")) +\n",
    "    geomText() { label = \"node\" } +\n",
    "    coordCartesian(-3 to 3, -1.5 to 1.5) +\n",
    "    themeVoid()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Kotlin",
   "language": "kotlin",
   "name": "kotlin"
  },
  "language_info": {
   "codemirror_mode": "text/x-kotlin",
   "file_extension": ".kt",
   "mimetype": "text/x-kotlin",
   "name": "kotlin",
   "nbconvert_exporter": "",
   "pygments_lexer": "kotlin",
   "version": "1.8.0-dev-3517"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
